PyTorch 中torch.nn. 与torch.nn.function.的区别
今天我在定义一个卷积网络的过程中,发现nn.Conv2d与nn.functional.conv2d看似都是相同的。
1 | class DogCat_Net(nn.Module): |
类似的还有很多,在卷积,激活,池化等操作中,nn.Conv2d与nn.functional.conv2d均很相似。
通过查看PyTorch的文档发现,例如torch.nn.Conv2d是一个类
torch.nn.functional.conv2d则更像一个函数:
简而言之:
- nn.Conv2d可以理解为一个Class类,需要继承nn.Module类
- nn.functional.conv2d可以理解为一个纯函数,由def function(input)定义
对于nn中定义的类,可以提取变化的学习参数。而nn.functional中的是函数,是一个固定的运算公式。
由于在深度学习中会有很多权重是不断变化的,所以需要采用类的方式,以确保参数改变后,仍能正确进行运算。
所以一般在建立网络模型时,在__init__函数中,通常使用nn中的类;而在forward函数中,通常使用nn.functional中的函数。
例如以下网络模型:
1 | class Dog_Cat(nn.Module): |
当网络模型使用了Dropout层时,其只需要在模型训练的时候进行使用,在模型测试时并不会使用它。
当Dropout层是使用nn.Dropout定义时,在模型训练时,可以通过model.train()开启它,在模型测试时,可以通过model.eval()关闭它。
但当Dropout层是用nn.functional.dropout定义的,那么在使用model.eval()后,也没办法关闭Dropout层。
以上提到了model.train()与model.eval(),那么它们的具体作用是什么呢?为什么要在模型训练与测试的时候加上这两段代码呢?
model.train()
如果模型中有BN层(Batch Normalization)和Dropout,需要在训练时添加model.train()。model.train()是保证BN层能够用到每一批数据的均值和方差。对于Dropout,model.train()是随机取一部分网络连接来训练更新参数。
model.eval()
如果模型中有BN层(Batch Normalization)和Dropout,在测试时添加model.eval()。model.eval()是保证BN层能够用全部训练数据的均值和方差,即测试过程中要保证BN层的均值和方差不变。对于Dropout,model.eval()是利用到了所有网络连接,即不进行随机舍弃神经元。
训练完train样本后,生成的模型model要用来测试样本。在model(test)之前,需要加上model.eval(),框架会自动把BN和Dropout固定住,不会取平均,而是用训练好的值,否则的话,有输入数据,即使不训练,它也会改变权值。这是model中含有BN层和Dropout所带来的的性质。
而在模型测试中,通常还会看见torch.no_grad(),它有什么作用呢?
- 用于停止autograd模块的工作,起到加速和节省显存的作用(具体行为就是停止gradient计算,从而节省了GPU算力和显存)
- 不会影响dropout和batchnorm层的行为
model.eval()与torch.no_grad()同时用,可以更加节省cpu算力,加速计算。